﻿/**
 * @file service_redis_client.hpp
 * @date 2021/05/10 21:03
 *
 * @author harrybao (harrybao@123u.com)
 *
 * @brief 服务redis客户端
 *
 * @version v1.0.0
 *
 * @copyright Copyright © 2021 All Rights Reserved 上海欢乐互娱网络科技有限公司
 *
 * @par history:
 * <table>
 * <tr><th>Date                     <th>Version     <th>Author <th>Description
 * <tr><td>2021/05/10 21:03         <td>1.0.0       <td>harrybao
 * <td>创建初始版本
 * </table>
 */

// #ifndef SERVICE_REDIS_CLIENT_HPP
// #define SERVICE_REDIS_CLIENT_HPP

#pragma once

#include "box/service_context.hh"
#ifdef _WIN32
#include "hiredis/win/hiredis.h"
#else
#include <hiredis.h>
#endif // _WIN32
#include "redis/redis.hh"
#include "service_tool.hpp"
#include "singleton.hpp"


namespace guild_service {
namespace common {

/**
 * @brief 服务redis客户端类
 *
 * ServiceBox提供的redis_client的包装类
 */
class service_redis_client : public service_tool {
 public:
  using service_context_type = kratos::service::ServiceContext;
  using redis_ptr_type = kratos::service::RedisPtr;
  using redis_handler_type = kratos::redis::RedisHandler;
  using redis_result_type = kratos::redis::Result;
  using redis_reply_type = redisReply;

  service_redis_client() : service_tool(), m_redis_ptr(nullptr) {}

  service_redis_client(service_context_type *context)
      : service_tool(), m_redis_ptr(std::move(context->new_redis())) {}

  virtual ~service_redis_client() = default;

  const redis_ptr_type &operator->() const { return m_redis_ptr; }

  /**
   * @brief 启动
   *
   * @return true 启动成功
   * @return false 启动失败
   */
  virtual bool start() override {
    if (!service_tool::start()) {
      return false;
    }

    return m_redis_ptr->start();
  }

  /**
   * @brief 停止
   *
   * @return true 停止成功
   * @return false 停止结束
   */
  bool stop() {
    if (!service_tool::stop()) {
      return false;
    }

    if (get_user_count() == 0) {
      if (!m_redis_ptr->stop()) {
        return false;
      }
    }

    return true;
  }

  /**
   * @brief 更新
   *
   * @param ms 当前时间戳
   * @return std::size_t 执行数量
   */
  std::size_t update(std::time_t ms) { return m_redis_ptr->update(ms); }

 private:
  /// redis客户端
  redis_ptr_type m_redis_ptr;
};

}  // namespace common

#define RedisClientSingleton(...)                              \
  (*common::singleton<common::service_redis_client>::instance( \
      __VA_ARGS__))  ///< redis客户端单例

using redis_handler_type =
    common::service_redis_client::redis_handler_type;  ///< redis回调函数类型
using redis_result_type =
    common::service_redis_client::redis_result_type;  ///< redis返回结果类型
using redis_reply_type =
    common::service_redis_client::redis_reply_type;  ///< redis返回原始类型

constexpr uint32_t kRedisCommonTimeOut =
    1000;  ///< redis通用同步超时时间（单位 毫秒）
constexpr uint32_t kRedisCommonTimeOutAsync =
    1000;  ///< redis通用异步超时时间（单位 毫秒）
constexpr char kRedisHost[] = "127.0.0.1";  ///< redis连接IP
constexpr uint32_t kRedisPort = 6379;       ///< redis连接端口
constexpr char kRedisUser[] = "";           ///< redis连接用户名
constexpr char kRedisPasswd[] = "";         ///< redis连接密码

constexpr char kRedisGetOp[] = "GET ";
constexpr char kRedisSetOp[] = "SET ";
constexpr char kRedisDelOp[] = "DEL ";
constexpr char kRedisHGetOp[] = "HGET ";
constexpr char kRedisHSetOp[] = "HSET ";
constexpr char kRedisHDelOp[] = "HDEL ";
constexpr char kRedisUnlinkOp[] = "UNLINK ";

/**
 * @brief 异步redis命令
 *
 * @param name 主机名
 * @param command 命令
 * @param timeout 超时时间（毫秒）
 * @param handler 执行完回调函数
 * @param user_data 用户数据
 * @return true 执行成功
 * @return false 执行失败
 */
inline static bool redis_command_async(const std::string &name,
                                       const std::string &command,
                                       std::time_t timeout,
                                       redis_handler_type handler,
                                       std::uint64_t user_data) {
  return RedisClientSingleton()->do_command(name, command, timeout, handler,
                                            user_data);
}

/**
 * @brief 同步redis命令
 *
 * @param name 主机名
 * @param command 命令
 * @param timeout 超时时间（毫秒）
 * @return redis_result_type 命令执行结果
 */
inline static std::unique_ptr<redis_result_type> redis_command_co(
    const std::string &name, const std::string &command, std::time_t timeout) {
  return RedisClientSingleton()->do_command_co(name, command, timeout);
}

/**
 * @brief redis客户端添加主机
 *
 * @param name 主机名
 * @param host 主机地址
 * @param port 端口
 * @param user 用户名
 * @param passwd 密码
 * @return true 添加主机成功
 * @return false 添加主机失败
 */
inline static bool redis_add_host(const std::string &name,
                                  const std::string &host, int port,
                                  const std::string &user,
                                  const std::string &passwd) {
  return RedisClientSingleton()->add_host(name, host, port, user, passwd);
}

/**
 * @brief redis回复是否为nil
 *
 * @param result redis结果
 * @return true nil
 * @return false 不是nil
 */
inline static bool redis_reply_is_nil(const redis_result_type &result) {
  auto *reply = reinterpret_cast<redis_reply_type *>(result.get_reply());
  return reply && reply->type == REDIS_REPLY_NIL;
}

}  // namespace guild_service
// #endif // REDIS_CLIENT_HPP
